<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>WebRTC Camera (Mobile)</title>
    <style>
        #localVideo {
            background-color: #CF3;
            width: 320px;
            height: 240px;
            margin: 10px;
        }
        #remoteVideo {
            background-color: #9CF;
            width: 320px;
            height: 240px;
            margin: 10px;
        }
        .video-container {
            display: flex;
            flex-wrap: wrap;
        }
        .controls {
            margin: 20px;
        }
        button {
            padding: 8px 15px;
            margin: 0 5px;
            cursor: pointer;
        }
    </style>
</head>
<body>
    <div class="video-container">
        <video id="localVideo" autoplay playsinline muted></video>
        <video id="remoteVideo" autoplay playsinline></video>
    </div>
    <div class="controls">
        <button id="toggleAudio">关闭麦克风</button>
        <button id="toggleVideo">关闭摄像头</button>
    </div>

    <script>

        // DOM元素
        const localVideo = document.getElementById('localVideo');
        const remoteVideo = document.getElementById('remoteVideo');
        const toggleAudioBtn = document.getElementById('toggleAudio');
        const toggleVideoBtn = document.getElementById('toggleVideo');

        // WebRTC状态变量
        let localStream;
        let peerConnection;
        let audioEnabled = true;
        let videoEnabled = true;
        
        // 信令服务器连接
        const ws = new WebSocket('wss://192.168.0.120:8888');

        // ==================== 核心等待机制 ====================
        let peerConnectionResolve;
        const peerConnectionReady = new Promise((resolve) => {
            peerConnectionResolve = resolve;
        });

        let remoteDescriptionResolve;
        const remoteDescriptionReady = new Promise((resolve) => {
            remoteDescriptionResolve = resolve;//把resolve函数保存到外部变量中，调用remoteDescriptionResolve就是调用resolve，就会改变promise的状态
        });

        // 初始化PeerConnection
        function createPeerConnection() {
            console.log('Creating peer connection...');
            peerConnection = new RTCPeerConnection({
                iceServers: [
                    { urls: 'stun:stun.l.google.com:19302' },
                    // 可添加其他STUN/TURN服务器
                ]
            });

            // 处理远程流
            peerConnection.ontrack = (event) => {
                console.log('Received track:', event.track.kind);
                if (!remoteVideo.srcObject && event.streams.length > 0) {
                    remoteVideo.srcObject = event.streams[0];
                }
            };

            // 处理ICE Candidate
            peerConnection.onicecandidate = (event) => {
                if (event.candidate) {
                    ws.send(JSON.stringify({
                        type: 'candidate',
                        candidate: event.candidate
                    }));
                    console.log('Sent ICE candidate');
                }
            };

            // 添加本地轨道
            if (localStream) {
                localStream.getTracks().forEach(track => {
                    peerConnection.addTrack(track, localStream);
                });
            }

            // 标记PeerConnection就绪
            peerConnectionResolve();
            console.log('PeerConnection ready');
        }

        // 处理Offer
        async function handleOffer(offer) {
            console.log('Handling offer...');
            if (!peerConnection) {
                await startMedia();
            }

            try {
                await peerConnection.setRemoteDescription(new RTCSessionDescription(offer));
                console.log('Remote description set');
                
                // 标记远程描述就绪
                remoteDescriptionResolve();
                
                const answer = await peerConnection.createAnswer();
                await peerConnection.setLocalDescription(answer);
                
                ws.send(JSON.stringify({
                    type: 'answer',
                    answer: answer
                }));
                console.log('Answer sent');
            } catch (error) {
                console.error('Error handling offer:', error);
            }
        }

        // 处理ICE Candidate
        async function handleCandidate(candidateData) {
            console.log('Handling ICE candidate...');
            
            try {
                // 等待两个必要条件
                await peerConnectionReady;
                await remoteDescriptionReady;
                
                console.log('Adding ICE candidate:', candidateData);
                await peerConnection.addIceCandidate(
                    new RTCIceCandidate(candidateData)
                );
                console.log('ICE candidate added successfully');
            } catch (error) {
                console.error('Error adding ICE candidate:', error);
            }
        }

        // WebSocket消息处理
        ws.onmessage = async (message) => {
            try {
                const data = JSON.parse(message.data);
                console.log('Received message:', data.type);

                switch (data.type) {
                    case 'offer':
                        await handleOffer(data.offer);
                        break;
                    case 'candidate':
                        await handleCandidate(data.candidate);
                        break;
                    default:
                        console.warn('Unknown message type:', data.type);
                }
            } catch (error) {
                console.error('Error processing message:', error);
            }
        };

        // 启动媒体设备
        async function startMedia() {
            try {
                console.log('Requesting media devices...');
                localStream = await navigator.mediaDevices.getUserMedia({
                    audio: true,
                    video: {
                        facingMode: "user",
                        width: { ideal: 640 },
                        height: { ideal: 480 }
                    }
                });
                
                localVideo.srcObject = localStream;
                createPeerConnection();
                console.log('Media started');
            } catch (error) {
                console.error('Error accessing media devices:', error);
                alert('无法访问摄像头/麦克风: ' + error.message);
            }
        }

        // 控制按钮事件
        toggleAudioBtn.addEventListener('click', () => {
            audioEnabled = !audioEnabled;
            if (localStream) {
                localStream.getAudioTracks().forEach(track => {
                    track.enabled = audioEnabled;
                });
            }
            toggleAudioBtn.textContent = audioEnabled ? '关闭麦克风' : '开启麦克风';
        });

        toggleVideoBtn.addEventListener('click', () => {
            videoEnabled = !videoEnabled;
            if (localStream) {
                localStream.getVideoTracks().forEach(track => {
                    track.enabled = videoEnabled;
                });
            }
            toggleVideoBtn.textContent = videoEnabled ? '关闭摄像头' : '开启摄像头';
        });

        // WebSocket事件
        ws.onopen = () => {
            console.log('WebSocket connected');
            ws.send(JSON.stringify({ type: 'register-mobile' }));
            startMedia();
        };

        ws.onerror = (error) => {
            console.error('WebSocket error:', error);
        };

        ws.onclose = () => {
            console.log('WebSocket disconnected');
        };
    </script>
</body>
</html>